package com.swak.job.timer;

import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;

import com.swak.job.timer.TimerTask.TaskFrag;
import com.swak.reactivex.threads.Contexts;
import com.swak.utils.Sets;

/**
 * 超级简单的定时任务
 * 
 * @author DELL
 */
public class Timer implements Runnable {

	private ScheduledExecutorService scheduler;
	private Set<CronTrigger> triggers;
	private final int coreThreads;
	private final int periodSeconds;
	private AtomicBoolean runable = new AtomicBoolean(true);

	/**
	 * 定义定时器
	 * 
	 * @param coreThreads
	 * @param periodSeconds
	 */
	public Timer(int coreThreads, int periodSeconds) {

		// 标注参数
		this.coreThreads = coreThreads;
		this.periodSeconds = periodSeconds;

		// 启动任务
		this.init();
	}

	/**
	 * 之后加入校验程序，校验任务的执行时长
	 * 
	 * @param tasks
	 */
	private void init() {
		// 任务执行器
		scheduler = Contexts.createScheduledContext("Job.Timer-", coreThreads, false, 60, TimeUnit.SECONDS);
		scheduler.scheduleAtFixedRate(this, 10, periodSeconds, TimeUnit.SECONDS);
		// 任务容器
		triggers = Sets.newConcurrentSet();
	}

	/**
	 * 启动计划任务
	 * 
	 * @param tasks
	 * @return
	 */
	public CronTrigger scheduleTasks(TimerTask task) {
		CronTrigger trigger = new CronTrigger(this, scheduler, task);
		triggers.add(trigger);
		return trigger;
	}

	/**
	 * 启动计划任务
	 * 
	 * @param tasks
	 * @return
	 */
	public CronTrigger scheduleTasks(String name, String cronExpression, boolean runObBoot,
			Function<TaskFrag, Object> func) {
		CronTrigger trigger = new CronTrigger(this, scheduler, new TimerTask(name, cronExpression, runObBoot, func));
		triggers.add(trigger);
		return trigger;
	}

	/**
	 * 周期的添加任务到定时任务中，也可以自己执行完成后自己添加也可以
	 */
	@Override
	public void run() {
		if (runable.get()) {
			triggers.stream().forEach((trigger) -> {
				trigger.schedule();
			});
		}
	}

	public void close() {
		try {
			runable.set(false);
			triggers.stream().forEach((trigger) -> {
				trigger.cancel();
			});
			triggers.clear();
		} catch (Exception e) {
		}
	}

	public static class CronTrigger {

		private final Timer timer;
		private final TimerTask task;
		private final ScheduledExecutorService scheduler;
		private volatile ScheduledFuture<?> future;
		private AtomicBoolean runable = new AtomicBoolean(true);

		public CronTrigger(Timer timer, ScheduledExecutorService scheduler, TimerTask task) {
			this.timer = timer;
			this.scheduler = scheduler;
			this.task = task;
		}

		public synchronized void cancel() {
			try {
				if (future != null) {
					future.cancel(true);
				}
				runable.set(false);
				timer.triggers.remove(this);
			} catch (Exception e) {
			}
		}

		public synchronized void schedule() {
			if (runable.get() && (future == null || future.isDone())) {
				future = this.scheduler.schedule(task, 0, TimeUnit.SECONDS);
			}
		}
	}
}
